#include "mystdio.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <malloc.h>
#include <assert.h>
#include <unistd.h>

int myfflush(My_FILE* stream)
{
  assert(stream);

  //将缓冲区内容刷新到指定的文件
  write(stream->fd, stream->outputbuffer, stream->current);//文件不识别\0，因此不用+1
  stream->current = 0; //刷新完缓冲区，将标记位置于0

  //强制刷新内核缓冲区
  fsync(stream->fd);
 
  return 0;
}

My_FILE* myfopen(const char *path, const char *mode)
{
  int flag = 0;

  if(strcmp(mode, "r") == 0) 
    flag |= O_RDONLY;
  else if(strcmp(mode, "w") == 0) 
    flag |= O_WRONLY|O_CREAT|O_TRUNC;
  else if(strcmp(mode, "a") == 0) 
    flag |= O_WRONLY|O_CREAT|O_APPEND;
  else{}

  int m = 0666;//默认创建文件权限
  int fd = 0;

  //调用系统接口
  if(flag & O_CREAT) 
    fd = open(path, flag, m);
  else 
    fd = open(path, flag);

  if(fd <0) 
  {
    //文件打开失败
    perror("open\n");
    return NULL;
  }

  //成功打开文件，创建文件结构体
  My_FILE* fp = (My_FILE*)malloc(sizeof(My_FILE));
  if(fp == NULL)
  {
    perror("malloc\n");
    close(fd);
    return NULL;
  }
  
  //初始化
  fp->fd = fd;
  fp->flag = 0;
  fp->current = 0;
  fp->flag |= BUFFELINE;//默认设置为行缓冲
  memset(fp->outputbuffer, '\0', sizeof(fp->outputbuffer));

  return fp;
}

int myfclose(My_FILE* fp)
{
  assert(fp);
  
  //刷新缓冲区
  if(fp->current > 0) myfflush(fp);
  
  close(fp->fd);
  
  //防止内存泄漏
  free(fp);
  fp = NULL;
  
  return 0;
}

size_t myfwrite(const void* ptr, size_t size, size_t nmemb, My_FILE* stream)
{
  //1.判断缓冲空间
  if(stream->current == NUM) 
    myfflush(stream); //满了直接刷新
  
  size_t mysize = NUM - stream->current;
  size_t insize = size * nmemb;//待写入数据大小

  if(mysize > insize)//空间>写入
  {
    memcpy(stream->outputbuffer + stream->current, ptr, insize);
    //更新数据
    stream->current += insize;
  }
  else//<
  {
    //有多少空间剩余，写入多少
    insize = mysize;
    memcpy(stream->outputbuffer + stream->current, ptr, insize);
    stream->current += insize;
  }

  //2.计划刷新缓冲区
  if(stream->flag & BUFFEALL)
  {
    if(stream->current == NUM) myfflush(stream);
  }
  else if(stream->flag & BUFFELINE)//行缓冲
  {
    if(stream->outputbuffer[stream->current - 1] == '\n')
      myfflush(stream);
  }
  else
  {
    //无缓冲，直接刷新内核缓冲区
    fsync(stream->fd);
  }

  return insize;
}














